`timescale 1ns/1ps
`include "Func.v"
module Kyber_Decoder(
    input  wire clk,rst_n,Start_Decode,
    input  wire [21:0] inst,

    output reg  [5:0] func,
    output reg  Poly_Start,
    output reg  [2:0] RAM_CTR,
    output reg  [3:0] R1_AddrAH,R1_AddrBH,R2_AddrAH,R2_AddrBH,R3_AddrAH,R3_AddrBH,
    output reg  Inst_Sel,

    output reg  [5:0] sha_func,
    output reg  [2:0] sha_RAM_CTR,
    output reg  [3:0] sha_rs1,sha_rs2,sha_dst,
    output reg  sha_Inst_Sel,

    input       sha_inst_done,
    input       inst_done

);
//*************** Inst_Sel **********************//
wire Inst_Sel_wire      =   inst[6];
reg [3:0] rs1          ;
reg [3:0] rs2          ;
reg [3:0] dst          ;
wire sha_Start_Decode   = ~Inst_Sel_wire & Start_Decode;
wire poly_Start_Decode  = Inst_Sel_wire & Start_Decode;

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        Inst_Sel <= 1'b0; 
    else if(inst_done) 
        Inst_Sel <= 1'b0;
    else if(poly_Start_Decode) 
        Inst_Sel <= inst[6];
end 

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n) 
        sha_Inst_Sel <= 1'b0;
    else if(sha_inst_done)
        sha_Inst_Sel <= 1'b1;
    else if(sha_Start_Decode)
        sha_Inst_Sel <= inst[6];
end 
//************************************************//

//**************  Poly_Start *****************//

always@(posedge clk or negedge rst_n) 
begin
    if(!rst_n) 
        Poly_Start<=1'b0;
    else if(poly_Start_Decode) 
        Poly_Start<=1;
    else 
        Poly_Start<=1'b0;
end


//***************** RAM_CTR ******************//

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        RAM_CTR <= 3'd0;
    end
    else if( poly_Start_Decode) begin
        RAM_CTR <= inst[21:19];
    end
end

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        sha_RAM_CTR <= 3'd0;
    end
    else if(sha_Start_Decode) begin
        sha_RAM_CTR <= inst[21:19];
    end
end
//********************************************//

//***************** rs1 ******************//

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        sha_rs1 <= 4'd0;
    end
    else if(sha_Start_Decode) begin
        sha_rs1 <= inst[18:15];
    end
end

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rs1 <= 4'd0;
    end
    else if(poly_Start_Decode) begin
        rs1 <= inst[18:15];
    end
end
//********************************************//

//***************** rs2 ******************//

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        sha_rs2 <= 4'd0;
    end
    else if(sha_Start_Decode) begin
        sha_rs2 <= inst[14:11];
    end
end

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rs2 <= 4'd0;
    end
    else if(poly_Start_Decode) begin
        rs2 <= inst[14:11];
    end
end
//********************************************//

//***************** dst ******************//

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        sha_dst <= 4'd0;
    end
    else if(sha_Start_Decode) begin
        sha_dst <= inst[10:7];
    end
end

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        dst <= 4'd0;
    end
    else if(poly_Start_Decode) begin
        dst <= inst[10:7];
    end
end
//********************************************//


//***************** func ******************//
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        func <= 6'h3f;
    end
    else if( poly_Start_Decode) begin
        func <= inst[5:0];
    end
end

always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        sha_func <= 6'h3f;
    end
    else if(sha_inst_done) begin
        sha_func <= 6'h3f;
    end
    else if(sha_Start_Decode) begin
        sha_func <= inst[5:0];
    end
end
//********************************************//

//****************** RAM_AddrH *****************// rs1 rs2 dst 存储块RAM选择/1:RAM2 0:RAM3
always@(*)
begin
    case(func)
    `NTT :  begin 
        R1_AddrAH =  rs2;                       R1_AddrBH =  rs2;          
        R2_AddrAH =  RAM_CTR[0] ? dst : rs1;    R2_AddrBH =  RAM_CTR[0] ? dst : rs1;  
        R3_AddrAH =  RAM_CTR[0] ? rs1 : dst;    R3_AddrBH =  RAM_CTR[0] ? rs1 : dst;  end
    `INTT:  begin 
        R1_AddrAH =  4'd0;                      R1_AddrBH =  4'd0; 
        R2_AddrAH =  RAM_CTR[0] ? dst : rs1 ;   R2_AddrBH =  RAM_CTR[0] ? dst : rs1; 
        R3_AddrAH =  RAM_CTR[0] ? rs1 : dst ;   R3_AddrBH =  RAM_CTR[0] ? rs1 : dst;  end
    `PWM1:  begin 
        R1_AddrAH =  4'd0;                      R1_AddrBH =  rs2; 
        R2_AddrAH =  RAM_CTR[0] ? dst : rs1 ;   R2_AddrBH =  RAM_CTR[0] ? dst + 1'b1 : 4'd0;
        R3_AddrAH =  RAM_CTR[0] ? rs1 : dst ;   R3_AddrBH =  RAM_CTR[0] ? 4'd0 : dst + 1'b1;  end
    `PWM2:  begin 
        R1_AddrAH =  4'd0;                      R1_AddrBH =  4'd0; 
        R2_AddrAH =  RAM_CTR[0] ? dst : rs1 ;   R2_AddrBH =  RAM_CTR[0] ? 4'd0 : rs2;
        R3_AddrAH =  RAM_CTR[0] ? rs1 : dst ;   R3_AddrBH =  RAM_CTR[0] ? rs2  : 0; end
    `PolyAdd:begin 
                case(RAM_CTR[0])
                1'b0: begin R3_AddrAH=dst; 
                        case(RAM_CTR[2:1])
                        2'b11   : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ; R2_AddrAH=rs1   ; R2_AddrBH = rs2   ; R3_AddrBH = 4'd0;  end      //110 :   R2_A读 R2_B读 R3_A写
                        2'b01   : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ; R2_AddrAH=4'd0  ; R2_AddrBH = rs2   ; R3_AddrBH = rs1 ;  end      //010 :   R1_B读 R3_B读 R3_A写
                        2'b10   : begin R1_AddrAH = 4'd0 ; R1_AddrBH = rs2  ; R2_AddrAH=4'd0  ; R2_AddrBH = rs1   ; R3_AddrBH = 4'd0;  end      //100 :   R1_B读 R2_B读 R3_A写
                        default : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ; R2_AddrAH=4'd0  ; R2_AddrBH = 4'd0  ; R3_AddrBH = 4'd0;  end
                        endcase
                    end
                1'b1: begin R2_AddrAH=dst; 
                        case(RAM_CTR[2:1])
                        2'b00       : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ;R2_AddrBH=4'd0 ; R3_AddrAH = rs1   ; R3_AddrBH = rs2   ;  end  // 101 :  R3_A读 R3_B读 R2_A写
                        2'b10       : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ;R2_AddrBH=rs1  ; R3_AddrAH = 4'd0  ; R3_AddrBH = rs2   ;  end  // 101 :  R2_B读 R3_B读 R2_A写 
                        2'b01       : begin R1_AddrAH = 4'd0 ; R1_AddrBH = rs2  ;R2_AddrBH=4'd0 ; R3_AddrAH = 4'd0  ; R3_AddrBH = rs1   ;  end  // 011 :  R3_B读 R1_B读 R2_A写
                        default     : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ;R2_AddrBH=rs1  ; R3_AddrAH = 4'd0  ; R3_AddrBH = 4'd0  ;  end
                        endcase
                    end 
                endcase
            end
    `Encode_ADD   :begin R1_AddrAH = 4'd8 ; R1_AddrBH = rs2 ;  R2_AddrAH = rs1  ; R2_AddrBH = 4'd0;  R3_AddrAH = 4'd0 ; R3_AddrBH = dst ; end     //R1_A是明文m的固定位置            
    `Decode_SUB   :begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0;  R2_AddrAH = dst  ; R2_AddrBH = rs1 ;  R3_AddrAH = 4'd0 ; R3_AddrBH = rs2 ; end
    `Compress10,`Compress4,`Decompress10,`Decompress4,`Compress11,`Compress5,`Decompress11,`Decompress5  :
                   begin    R1_AddrAH =  4'd0 ;                     R1_AddrBH = 4'd0 ;
                            R2_AddrAH =  RAM_CTR[0] ? dst : rs1;    R2_AddrBH =  RAM_CTR[0] ? dst : rs1; 
                            R3_AddrAH =  RAM_CTR[0] ? rs1 : dst;    R3_AddrBH =  RAM_CTR[0] ? rs1 : dst;  end
    // `Compare10,`Compare11,`Compare4,`Compare5:
    //                begin
    //                     R1_AddrAH = 4'd0 ;      R1_AddrBH = 4'd0 ;
    //                     R2_AddrAH = rs1  ;      R2_AddrBH = rs2  ;
    //                     R3_AddrAH = 4'd0 ;      R3_AddrBH = 4'd0 ;
    //                end
    // `PolyMov:
    // begin
    //     case(RAM_CTR[0])
    //     1'b0:    begin R2_AddrAH = dst; R2_AddrBH = dst; R1_AddrAH = rs1; R1_AddrBH = rs1; end
    //     1'b1:    begin R1_AddrAH = dst; R1_AddrBH = dst; R2_AddrAH = rs1; R2_AddrBH = rs1; end
    //     endcase
    // end
    default: begin R1_AddrAH=0;R1_AddrBH=0;R2_AddrAH=0;R2_AddrBH=0; R3_AddrAH=0;R3_AddrBH=0;end 
    endcase
end



// always@(*)
// begin
//     case(func)
//     `NTT :  begin 
//         R1_AddrAH =  rs2;                       R1_AddrBH =  rs2;          
//         R2_AddrAH =  RAM_CTR[0] ? dst : rs1;    R2_AddrBH =  RAM_CTR[0] ? dst : rs1;  
//         R3_AddrAH =  RAM_CTR[0] ? rs1 : dst;    R3_AddrBH =  RAM_CTR[0] ? rs1 : dst;  end
//     `INTT:  begin 
//         R1_AddrAH =  4'd0;                      R1_AddrBH =  4'd0; 
//         R2_AddrAH =  RAM_CTR[0] ? dst : rs1 ;   R2_AddrBH =  RAM_CTR[0] ? dst : rs1; 
//         R3_AddrAH =  RAM_CTR[0] ? rs1 : dst ;   R3_AddrBH =  RAM_CTR[0] ? rs1 : dst;  end
//     `PWM1:  begin 
//         R1_AddrAH =  RAM_CTR[2] ? rs1 : 4'd0;   R1_AddrBH =  4'd0; 
//         R2_AddrAH = ~RAM_CTR[2] ? rs1 : 4'd0;   R2_AddrBH = rs2;
//         R3_AddrAH =  dst;                       R3_AddrBH = dst + 1'b1;  end
//     `PWM2:  begin R1_AddrAH =  4'd0;                    R1_AddrBH =  4'd0; 
//                   R2_AddrAH =  RAM_CTR[0] ? dst : rs1 ; R2_AddrBH =  RAM_CTR[0] ? 4'd0 : rs2;
//                   R3_AddrAH =  RAM_CTR[0] ? rs1 : dst ; R3_AddrBH =  RAM_CTR[0] ? rs2  : 0; end
//     `PolyAdd:begin 
//                 case(RAM_CTR[0])
//                 1'b0: begin R3_AddrAH=dst; 
//                         case(RAM_CTR[2:1])
//                         2'b11   : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ; R2_AddrAH=rs1   ; R2_AddrBH = rs2   ; R3_AddrBH = 4'd0;  end 
//                         2'b01   : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ; R2_AddrAH=4'd0  ; R2_AddrBH = rs1   ; R3_AddrBH = rs2 ;  end
//                         2'b10   : begin R1_AddrAH = 4'd0 ; R1_AddrBH = rs1  ; R2_AddrAH=4'd0  ; R2_AddrBH = rs2   ; R3_AddrBH = 4'd0;  end
//                         default : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ; R2_AddrAH=4'd0  ; R2_AddrBH = 4'd0  ; R3_AddrBH = 4'd0;  end
//                         endcase
//                     end
//                 1'b1: begin R2_AddrAH=dst; 
//                         case(RAM_CTR[2:1])
//                         2'b00       : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ;R2_AddrBH=4'd0 ; R3_AddrAH = rs1   ; R3_AddrBH = rs2   ;  end 
//                         2'b10       : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ;R2_AddrBH=rs1  ; R3_AddrAH = 4'd0  ; R3_AddrBH = rs2   ;  end
//                         2'b01       : begin R1_AddrAH = 4'd0 ; R1_AddrBH = rs2  ;R2_AddrBH=rs1  ; R3_AddrAH = 4'd0  ; R3_AddrBH = 4'd0  ;  end
//                         default     : begin R1_AddrAH = 4'd0 ; R1_AddrBH = 4'd0 ;R2_AddrBH=4'd0 ; R3_AddrAH = 4'd0  ; R3_AddrBH = 4'd0  ;  end
//                         endcase
//                     end 
//                 endcase
//             end

// //    `Encode_ADD   :begin R1_AddrAH = rs1; R1_AddrBH = rs2; R2_AddrBH = 4'd15; R2_AddrAH = dst  ; end   
//     `Encode_ADD   :begin R1_AddrAH = 4'd15; R1_AddrBH = rs2;  R2_AddrAH = rs1  ; R2_AddrBH = 4'd0;  R3_AddrAH = dst  ; R3_AddrBH = 4'd0; end                 
//     `Decode_SUB   :begin R1_AddrAH = rs1  ; R1_AddrBH = rs2;  R2_AddrAH = 4'd15; R2_AddrBH = 4'd0;  R3_AddrAH = 4'd0 ; R3_AddrBH = 4'd0;end
//     `Compress10,`Compress4,`Decompress10,`Decompress4,`Compress11,`Compress5,`Decompress11,`Decompress5  :
//                    begin    R1_AddrAH = 4'd0 ;                   R1_AddrBH = 4'd0 ;
//                             R2_AddrAH =  RAM_CTR[0] ? dst : rs1; R2_AddrBH =  RAM_CTR[0] ? dst : rs1; 
//                             R3_AddrAH = ~RAM_CTR[0] ? dst : rs1; R3_AddrBH = ~RAM_CTR[0] ? dst : rs1;  end
//     `Compare10,`Compare11,`Compare4,`Compare5:
//                    begin
//                         R1_AddrAH = rs1;    R1_AddrBH = rs2;
//                         R2_AddrAH = rs1;    R2_AddrBH = rs2;
//                         R3_AddrAH = 4'd0  ; R3_AddrBH = 4'd0  ;
//                    end
//     // `PolyMov:
//     // begin
//     //     case(RAM_CTR[0])
//     //     1'b0:    begin R2_AddrAH = dst; R2_AddrBH = dst; R1_AddrAH = rs1; R1_AddrBH = rs1; end
//     //     1'b1:    begin R1_AddrAH = dst; R1_AddrBH = dst; R2_AddrAH = rs1; R2_AddrBH = rs1; end
//     //     endcase
//     // end
//     default: begin R1_AddrAH=0;R1_AddrBH=0;R2_AddrAH=0;R2_AddrBH=0; R3_AddrAH=0;R3_AddrBH=0;end 
//     endcase
// end


//********************************************//

endmodule